#include <iostream>
#include <cmath>
#include <vector>
#include <unordered_map>
#include <functional>
#include <fstream>
#define weight 500
#define epision 1e-6
struct Vertex{
    int x;
    int y;
    int z;
    Vertex() = default;  
    Vertex(int x, int y, int z) : x(x), y(y), z(z) {}
    bool operator==(const Vertex& other) const {
        return x == other.x && y == other.y && z == other.z;
    }
};


// face - center cell - center
struct Gen_Vertex{
    double x;
    double y;
    double z;
    Gen_Vertex() = default;
    Gen_Vertex(double x, double y, double z) : x(x), y(y), z(z) {}
    bool operator==(const Gen_Vertex& other) const  {
        return (fabs(x-other.x) < epision) && (fabs(y-other.y) < epision) && (fabs(y-other.y) < epision);  
    }
};

namespace std {
    //300进制的数
    template <>
    struct hash<Vertex> {
        size_t operator()(const Vertex& v) const {
            return hash<int>()(v.x*weight*weight + v.y*weight + v.z);
        }
    };
}

typedef std::unordered_map<Vertex, int> VertexHashTable;

typedef std::unordered_map<Vertex, int> FaceHashTable;

typedef unsigned long VID;

struct Face{
    VID v1;
    VID v2;
    VID v3;
    VID v4;
};

typedef unsigned long FID;


// based on the mark rule, use vid_list to infer a cell
struct Cell_Vertex{
    VID v1;
    VID v2;
    VID v3;
    VID v4;
    VID v5;
    VID v6;
    VID v7;
    VID v8;
};

//bottom left front right back top, use fid_list to infer a cell
struct Cell_Face{
    FID f1;
    FID f2;
    FID f3;
    FID f4;
    FID f5;
    FID f6;
};



class Cube{
public:
    enum SmallCubeStatus{
        INNER_Y_INC = 0,
        INNER_X_INC,
        OUTER_Y_INC,
        OUTER_X_INC,
        INNER_BOUND,
        OUTER_BOUND,
        TOP,
        TOP_Y_BOUND,
        TOP_X_BOUND,
        TOP_X_Y_BOUND
    };

    Cube(int n, bool enable_flatten_vertex_id = true);

    // 2. 禁用所有编译器可能隐式生成的构造
    Cube() = delete;
    Cube(const Cube&) = delete;
    Cube& operator=(const Cube&) = delete;
    Cube(Cube&&) = delete;
    Cube& operator=(Cube&&) = delete;
    static int get_points_num(int n);
    static int get_faces_num(int n);
    static int get_cells_num(int n);
    static int get_polyhedrons_num(int n);
    void fill_till_n_times();
    void fill_one_time(int n);
    void vertex_face_cell_nums_restrict(int n);
    void debug();
    void init();
    Vertex get_one_vertex(int vertex_id);
    Vertex get_pesudo_face_center_point(Face f);
    Vertex get_pesudo_cell_center_point(Cell_Vertex c);
    VID    get_one_vertex_id(Vertex &v);
    FID    get_one_face_id(Face &f);
    void register_one_vertex_in_hashtable(Vertex v);
    void register_one_face_in_hashtable(Vertex v);
    void display_vertex_using_id(int vertex_id);
    void display_vertex_table(const std::string& filename);
    void display_face_table(const std::string& filename);
    void display_cell_vertex_table(const std::string& filename);
    void display_cell_face_table(const std::string& filename);
    void register_one_cell_into_face_table(Vertex v[], SmallCubeStatus st);
    void fulfill_cells_faces_table_at_last();
    void debug_one_vertex(Vertex v);
    bool has_duplicate_element(VID vid_list[]);
    double get_face_center_distance(FID f);

    inline const char* status_to_string(SmallCubeStatus s) {
        static const char* tbl[] = {
            "INNER_Y_INC",
            "INNER_X_INC",
            "OUTER_Y_INC",
            "OUTER_X_INC",
            "INNER_BOUND",
            "OUTER_BOUND",
            "TOP",
            "TOP_Y_BOUND",
            "TOP_X_BOUND",
            "TOP_X_Y_BOUND"
        };
    // 如果担心越界，可以再加一行 assert
        return tbl[static_cast<int>(s)];
    }


private:
    int n_;  // point to iteration loops
    int curr_n_;  //point to curr loops times
    std::vector<Vertex> vertexs_table_; // easy to get
    std::vector<Face> faces_table_;  // easy to get
    std::vector<Cell_Vertex> cells_vertexs_table_;  // easy to get
    std::vector<Cell_Face>   cells_faces_table_;  //easy to get
    VertexHashTable vertexhashtable_;  // vertex to vertex_id;
    FaceHashTable   facehashtable_;
    int vertex_idx_;
    int face_idx_;
    bool enable_flatten_vertex_id_ = false;
};

class Solution{
public:
    static int get_num();
private:
};